﻿#region Using Directives

using System;
using System.Globalization;
using System.IO;

#endregion Using Directives


namespace Kongo.Tags
{
    internal class NowTag : BaseTag
    {
        #region Fields

        private string format;

        #endregion Fields


        #region Methods

        public override void Render(Context context, TextWriter output)
        {
            // We're always working with the present date & time
            DateTime dt = DateTime.Now;

            // Translate each char.
            // You might be able to squeeze a little more performance out of this by using
            // custom conversions rathern that DateTime.ToString() formats.
            for(int i = 0; i < format.Length; i++)
            {
                char ch = format[i];
                switch (ch)
                {
                    case 'a':
                        output.Write(dt.Hour >= 11 ? "p.m." : "a.m.");
                        continue;

                    case 'A':
                        output.Write(dt.Hour >= 11 ? "AM" : "PM");
                        continue;

                    case 'b':
                        output.Write(dt.ToString("MMM").ToLower());
                        continue;

                    case 'B':
                        continue;

                    case 'd':
                        output.Write(dt.ToString("dd"));
                        continue;

                    case 'D':
                        output.Write(dt.ToString("ddd"));
                        continue;

                    case 'f':
                        output.Write(dt.ToString("h"));
                        if (dt.Minute != 0)
                        {
                            output.Write(":");
                            output.Write(dt.ToString("mm"));
                        }
                        continue;

                    case 'F':
                        output.Write(dt.ToString("MMMM"));
                        continue;

                    case 'g':
                        output.Write(dt.ToString("h"));
                        continue;

                    case 'G':
                        output.Write(dt.ToString("H"));
                        continue;

                    case 'h':
                        output.Write(dt.ToString("hh"));
                        continue;

                    case 'H':
                        output.Write(dt.ToString("HH"));
                        continue;

                    case 'i':
                        output.Write(dt.ToString("mm"));
                        continue;

                    case 'I':
                        continue;

                    case 'j':
                        output.Write(dt.ToString("d"));
                        continue;

                    case 'l':
                        output.Write(dt.ToString("dddd"));
                        continue;

                    case 'L':
                        output.Write(DateTime.IsLeapYear(dt.Year) ? "True" : "False");
                        continue;

                    case 'm':
                        output.Write(dt.ToString("MM"));
                        continue;

                    case 'M':
                        output.Write(dt.ToString("MMM"));
                        continue;

                    case 'n':
                        output.Write(dt.ToString("M"));
                        continue;

                    case 'N':
                        string month = dt.ToString("MMMM");
                        if (month.Length > 5)
                            month = String.Format("{0:MMM.", dt);
                        output.Write(month);
                        continue;

                    case 'O':
                        output.Write("{0:zz00}", dt);
                        continue;

                    case 'P':
                        if (dt.Minute == 0)
                        {
                            if (dt.Hour == 0)
                                output.Write("midnight");
                            else if (dt.Hour == 11)
                                output.Write("noon");
                            else
                            {
                            }
                        }
                        else
                        {
                            // TODO
                        }
                        continue;

                    case 'r':
                        // TODO
                        continue;

                    case 's':
                        output.Write(dt.ToString("ss", DateTimeFormatInfo.InvariantInfo));
                        continue;

                    case 'S':
                        // TODO
                        continue;

                    case 't':
                        // TODO
                        continue;

                    case 'T':
                        // TODO
                        continue;

                    case 'U':
                        // TODO
                        continue;

                    case 'w':
                        // TODO
                        continue;

                    case 'W':
                        // TODO
                        continue;

                    case 'y':
                        output.Write(dt.ToString("yy", DateTimeFormatInfo.InvariantInfo));
                        continue;

                    case 'Y':
                        output.Write(dt.ToString("yyyy", DateTimeFormatInfo.InvariantInfo));
                        continue;

                    case 'z':
                        // TODO
                        continue;

                    case 'Z':
                        // TODO
                        continue;

                    case '\\': // Escape char
                        if (i + 1 < format.Length)
                            output.Write(format[i + 1]);
                        continue;

                    default:
                        output.Write(ch);
                        continue;
                }
            }
            
        }

        #endregion Methods


        #region Constructors

        public NowTag(string[] args) : base(args)
        {
            // Look for a single string constant argument
            if (args.Length != 2)
                throw CreateSyntaxException(); // TODO Specific

            if (!args[1].StartsWith("\"") && !args[1].EndsWith("\"") && !(args[1].Length >= 2))
                throw CreateSyntaxException(); // TODO Specific

            this.format = Helpers.UnescapeStringConstant(args[1]);
        }

        #endregion Constructors


        #region Types

        public class NowTagCreator : ITagCreator
        {
            #region Methods

            public Tag Create(string[] args)
            {
                return new NowTag(args);
            }

            #endregion Methods
        }

        #endregion Types
    }
}
